﻿#region [ License information          ]
/* ************************************************************
 *
 * Copyright (c) Bjørn Bouet Smith, 2012
 *
 * This source code is subject to terms and conditions of 
 * Microsoft Public License (Ms-PL).
 * 
 * A copy of the license can be found in the license.txt
 * file at the root of this distribution. If you can not 
 * locate the License, please send an email to bjornsmith@gmail.com
 * 
 * By using this source code in any fashion, you are 
 * agreeing to be bound by the terms of the Microsoft 
 * Public License.
 *
 * You must not remove this notice, or any other, from this
 * software.
 *
 * ************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace Smith.BuildExtensions.ConfigurationTransformation
{
    [XmlRoot(ElementName = "settings")]
    public class ConfigSettings
    {
        private static readonly XmlSerializer ConfigSerializer = new XmlSerializer(typeof(ConfigSettings));

        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigSettings"/> class.
        /// </summary>
        public ConfigSettings()
        {
            ValueSettings = new List<ValueSetting>();
            SectionSettings = new List<SectionSetting>();
        }

        [XmlElement(ElementName = "add")]
        public List<ValueSetting> ValueSettings
        {
            get;
            set;
        }

        [XmlElement(ElementName = "addsection")]
        public List<SectionSetting> SectionSettings
        {
            get;
            set;
        }

        [XmlAttribute(AttributeName="ConfigSource")]
        public string ConfigSource
        {
            get;
            set;
        }

        private List<ConfigSetting> configSettings;

        [XmlIgnore]
        public List<ConfigSetting> Settings
        {
            get
            {
                return configSettings ?? (configSettings = GetSettings());
            }
        }
        
        public static ConfigSettings LoadFromFile(string fileName)
        {
            List<string> fileNames = new List<string>();
            return RecursiveLoad(fileName, fileNames);
        }
        
        private static ConfigSettings RecursiveLoad(string fileName, List<string> fileNames)
        {
            if(fileNames.Contains(fileName))
            {
                throw new InvalidOperationException("Cycle detected in ConfigSource");
            }
            
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                ConfigSettings configSettings = (ConfigSettings)ConfigSerializer.Deserialize(fs);
                if (configSettings.ConfigSource == null)
                {
                    return configSettings;
                }
                fileNames.Add(fileName);

                // Create new filename and call method recursively
                string newFileName = Path.Combine(fileName.Substring(0, fileName.LastIndexOf(Path.DirectorySeparatorChar)), configSettings.ConfigSource);
                return RecursiveLoad(newFileName, fileNames);
            }
        }

        private List<ConfigSetting> GetSettings()
        {
            List<ConfigSetting> settings = new List<ConfigSetting>();
            settings.AddRange(SectionSettings);
            settings.AddRange(ValueSettings);
            return settings;
        }

    }
}
